﻿using CKS2320.Common;
using CKS2320.Common.Model;
using CKS2320.Common.Utils;
using CKS2320.Controller;
using CKS2412.Controller.Common.Utils;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using NPOI.POIFS.Crypt.Dsig;
using Org.BouncyCastle.Asn1.Ocsp;
using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace CKS2412.Controller.Action
{
    public class Op20Action_Service
    {
        #region 与主界面log日志方法绑定
        public delegate void AddLogHandler(string content, string source = "OP20");
        public static AddLogHandler AddLogEventHandler;
        #endregion

        SystemSettingModel sysModel = new SystemSettingModel();
        int? lastTc_A = 0;//A通道最后一次执行任务
        int? lastTc_B = 0;//B通道最后一次执行任务

        public Op20Action_Service()
        {

        }

        /// <summary>
        /// 监听PLC数据
        /// </summary>
        /// <param name="plc">plc对象</param>
        /// <returns></returns>
        public async Task PlcRunOp20(PLCController plc)
        {
            if (plc != null)
            {
                AddLogEventHandler?.Invoke("OP20开启监听数据变化");
                while (true)
                {

                    try
                    {
                        if (plc.CheckConnect())
                            await Process(plc);
                    }
                    catch (Exception ex)
                    {
                        AddLogEventHandler?.Invoke("OP20未知异常：" + ex.Message);
                    }
                    //GC.Collect();
                    await Task.Delay(200);
                }
                //AddLogEventHandler?.Invoke("OP20连接断开，监听结束");
            }
        }

        private async Task Process(PLCController plc)
        {
            #region A件
            int? startUpload = plc?.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.UploadStart_OP20));//读取上传请求
                                                                                                                            //int? uploadCode = plc?.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.UploadCode_OP20));//读取上传代号

            int? statusA = plc?.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.ProductStatusA_OP20));//A件状态
            if (startUpload == 1 && startUpload != lastTc_A) //
            {
                try
                {
                    //if (uploadCode == 10 || uploadCode == 12)//10：通道A上传 12：全部上传
                    if (statusA == 1)
                    {
                        await PlcRunType(plc, "A");
                        await Task.Delay(500);
                    }
                    lastTc_A = startUpload;
                }
                catch (Exception ex)
                {
                    plc?.WriteInt(SignalAdrSetting.dbOp20_FromPc, SignalAdrSetting.UploadDoneA_OP20, 2);
                    lastTc_A = startUpload;
                    AddLogEventHandler?.Invoke("A件OP20发生错误  " + ex.Message);
                }
            }
            else if (startUpload == 0)
            {
                lastTc_A = startUpload;
                plc?.WriteInt(SignalAdrSetting.dbOp20_FromPc, SignalAdrSetting.UploadDoneA_OP20, 0);
                await Task.Delay(200);
            }
            #endregion

            #region B件
            //int? startUploadB = plc?.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.UploadStartB_OP20));//读取A件上传请求
            int? statusB = plc?.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.ProductStatusB_OP20));//B件状态
            if (startUpload == 1 && startUpload != lastTc_B)
            {
                try
                {
                    //if (uploadCode == 11 || uploadCode == 12)//11：通道B上传 12：全部上传
                    if (statusB == 1)//有产品
                    {
                        await PlcRunType(plc, "B");
                        await Task.Delay(500);
                    }
                    lastTc_B = startUpload;
                }
                catch (Exception ex)
                {
                    plc?.WriteInt(SignalAdrSetting.dbOp20_FromPc, SignalAdrSetting.UploadDoneB_OP20, 2);
                    lastTc_B = startUpload;
                    AddLogEventHandler?.Invoke("B件OP20发生错误  " + ex.Message);
                }
            }
            else if (startUpload == 0)
            {
                lastTc_B = startUpload;
                plc?.WriteInt(SignalAdrSetting.dbOp20_FromPc, SignalAdrSetting.UploadDoneB_OP20, 0);
                await Task.Delay(200);
            }
            #endregion
        }

        /// <summary>
        /// 执行AB件
        /// </summary>
        /// <param name="plc"></param>
        /// <param name=""></param>
        /// <returns></returns>
        private async Task PlcRunType(PLCController plc, string channelCode)
        {
            AddLogEventHandler?.Invoke(channelCode + "件" + "OP20开始读取PLC数据");
            var uploadResult = PlcUploadData(plc, channelCode);
            if (uploadResult != null && uploadResult.Code == 1)
            {
                AddLogEventHandler?.Invoke(channelCode + "件  " + "OP20开始数据解析");

                //保存数据
                var dataSaveResult = SaveData(uploadResult.Data, channelCode);
                if (dataSaveResult != null && dataSaveResult?.Code == 1)
                {
                    //返回读取结束
                    //if (channelCode.ToUpper() == "A")
                    //{
                    //    plc.WriteInt(SignalAdrSetting.dbOp20, SignalAdrSetting.UploadDoneA_OP20, 1);
                    //}
                    //if (channelCode.ToUpper() == "B")
                    //{
                    //    plc.WriteInt(SignalAdrSetting.dbOp20, SignalAdrSetting.UploadDoneB_OP20, 1);
                    //}
                    await Task.Delay(200);
                    if (channelCode == "A")
                    {
                        plc.WriteInt(SignalAdrSetting.dbOp20_FromPc, SignalAdrSetting.UploadDoneA_OP20, 1);//这里是不是也需要增加个代号？？？
                    }
                    else
                    {
                        plc.WriteInt(SignalAdrSetting.dbOp20_FromPc, SignalAdrSetting.UploadDoneB_OP20, 1);
                    }
                    AddLogEventHandler?.Invoke("OP20本次数据读取已完成");
                }
                else
                {
                    //if (channelCode.ToUpper() == "A")
                    //{
                    //    plc.WriteInt(SignalAdrSetting.dbOp20, SignalAdrSetting.UploadDoneA_OP20, 2);
                    //}
                    //if (channelCode.ToUpper() == "B")
                    //{
                    //    plc.WriteInt(SignalAdrSetting.dbOp20, SignalAdrSetting.UploadDoneB_OP20, 2);
                    //}
                    await Task.Delay(200);
                    if (channelCode == "A")
                    {
                        plc.WriteInt(SignalAdrSetting.dbOp20_FromPc, SignalAdrSetting.UploadDoneA_OP20, 2);
                    }
                    else
                    {
                        plc.WriteInt(SignalAdrSetting.dbOp20_FromPc, SignalAdrSetting.UploadDoneB_OP20, 2);
                    }
                    AddLogEventHandler?.Invoke("OP20数据保存失败" + dataSaveResult?.Message);
                }
            }
            else
            {
                if (channelCode == "A")
                {
                    plc.WriteInt(SignalAdrSetting.dbOp20_FromPc, SignalAdrSetting.UploadDoneA_OP20, 2);
                }
                else
                {
                    plc.WriteInt(SignalAdrSetting.dbOp20_FromPc, SignalAdrSetting.UploadDoneB_OP20, 2);
                }
                AddLogEventHandler?.Invoke(channelCode + "件  " + "OP20数据异常，内容不存在值");
            }
        }

        private ResultReturn PlcUploadData(PLCController plc, string channelCode)
        {
            if (plc != null)
            {
                int dataStartAdrOffset = 0;//读取偏移量起始地址
                //bool? startUpload = plc.ReadBool(SignalAdrSetting.dbOp10, SignalAdrSetting.UploadStart_OP10);//收到上传信号
                string sn = "";
                string[] strAry = new string[2];
                switch (channelCode.ToUpper())
                {
                    case "A":
                        strAry = SignalAdrSetting.SerialNumberA_OP20.Split('.');
                        Thread.Sleep(50);
                        sn = plc.ReadString(SignalAdrSetting.dbOp20, Convert.ToInt32(strAry[0]), Convert.ToInt32(strAry[1]));
                        break;
                    case "B":
                        strAry = SignalAdrSetting.SerialNumberB_OP20.Split('.');
                        Thread.Sleep(50);
                        sn = plc.ReadString(SignalAdrSetting.dbOp20, Convert.ToInt32(strAry[0]), Convert.ToInt32(strAry[1]));
                        break;
                }
                AddLogEventHandler?.Invoke(channelCode + "件OP20产品二维码：" + sn);
                List<DetectionDetail> details = new List<DetectionDetail>();
                Dictionary<string, int> detectionTypeList = new();
                detectionTypeList = StringUtils.GetDataOffset("OP20");

                bool? detectionVestigitalResult = false;//残留结果
                bool? detectionDirectionResult = false;//方向结果
                bool? detectionResult_ccd = false;//获取相机检测结果
                bool? detectionAcResult = false;//获取耐压AC结果
                bool? detectionDcResult = false;//获取耐压DC结果
                bool? finalResult = false;//总结果
                bool? totalLenght = false;//总长结果
                Thread.Sleep(50);
                switch (channelCode.ToUpper())
                {
                    case "A":
                        dataStartAdrOffset = SignalAdrSetting.dataStartOffsetA_OP20;
                        detectionVestigitalResult = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.CcdResult_VestigitalA)) == 1 ? true : false;
                        detectionDirectionResult = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.CcdResult_DirectionA)) == 1 ? true : false;
                        detectionAcResult = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.WithstandVoltageAcResultA)) == 1 ? true : false;
                        detectionDcResult = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.WithstandVoltageDcResultA)) == 1 ? true : false;
                        finalResult = false;//总结果
                        finalResult = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.FinalResultA_OP20)) == 1 ? true : false;
                        totalLenght = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.TotalLengthA_OP20)) == 1 ? true : false;
                        break;
                    case "B":
                        dataStartAdrOffset = SignalAdrSetting.dataStartOffsetB_OP20;
                        detectionVestigitalResult = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.CcdResult_VestigitalB)) == 1 ? true : false;
                        detectionDirectionResult = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.CcdResult_DirectionB)) == 1 ? true : false;
                        detectionAcResult = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.WithstandVoltageAcResultB)) == 1 ? true : false;
                        detectionDcResult = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.WithstandVoltageDcResultB)) == 1 ? true : false;
                        finalResult = false;//总结果
                        finalResult = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.FinalResultB_OP20)) == 1 ? true : false;
                        totalLenght = plc.ReadIntOne(SignalAdrSetting.dbOp20, Convert.ToInt32(SignalAdrSetting.TotalLengthB_OP20)) == 1 ? true : false;
                        break;
                }
                detectionResult_ccd = (detectionVestigitalResult == true && detectionDirectionResult == true) ? true : false;
                details.AddRange(UploadDataReal(plc, channelCode, SignalAdrSetting.dbOp20, dataStartAdrOffset, detectionTypeList, "OP20", sn, 0));
                AddLogEventHandler?.Invoke(channelCode + "件OP20获取总结果：" +  finalResult.ToString());
                //bool? finalResult = (detectionResult_ccd == true && detectionDcResult == true) ? true : false;//相机ok和耐压ok才最终结果ok
                VoltageWithstandModel voltageWithstand = new()
                {
                    StationCode = "OP20",
                    PartCode = sn,
                    CameraDetectionResult = detectionResult_ccd,
                    VoltageWithstandResult = detectionDcResult,
                    VoltageWithstandResultAC = detectionAcResult,   
                    TotalLengthResult = totalLenght,//2025/8/27新增
                    Result = finalResult,
                    RunType = channelCode,
                    detaillist = details
                };
                return MessageInfoUtils.Success(voltageWithstand);
            }
            return MessageInfoUtils.Fail();
        }

        /// <summary>
        /// 批量读取检测数据
        /// </summary>
        /// <param name="plc">plc对象</param>
        /// <param name="channelCode">通道号</param>
        /// <param name="db">DB块</param>
        /// <param name="dataStartOffset">数据起始便宜</param>
        /// <param name="contentTypeList">字典</param>
        /// <param name="dataSource">数据来源</param>
        /// <param name="partcode">产品二维码</param>
        /// <param name="detectedStatus">检测项状态</param>
        /// <returns></returns>
        private List<DetectionDetail>? UploadDataReal(PLCController plc, string channelCode, int db, int dataStartOffset, Dictionary<string, int> contentTypeList, string dataSource, string partcode, int detectedStatus)
        {
            List<DetectionDetail> details = new();
            try
            {
                // 115个Real类型数据，每个数据占4个字节
                int numBytes = contentTypeList.Count * 4;
                Thread.Sleep(100);
                byte[] dataS = plc.ReadBytes(db, dataStartOffset, numBytes);

                // 每个Real类型数据占4个字节
                float[] dataRead = new float[numBytes / 4];
                for (int i = 0; i < dataRead.Length; i++)
                {
                    byte[] floatData = new byte[4];
                    // 从原始数据中复制出一个 float 长度的数据块
                    Array.Copy(dataS, i * 4, floatData, 0, 4);
                    // 反转字节顺序
                    Array.Reverse(floatData);
                    dataRead[i] = BitConverter.ToSingle(floatData, 0);
                }
                string result = string.Join(",", dataRead);
                //Log4NetAppend(runType.ToString() + "件获取PLC地址值：" + result, dataIp);
                AddLogEventHandler?.Invoke(channelCode + "件OP20获取PLC地址值：" + result);
                for (int i = 0; i < contentTypeList.Count; i++)
                {
                    var contentType = contentTypeList.ElementAt(i);
                    details.Add(new DetectionDetail()
                    {
                        DetectedData = (float)Math.Round(dataRead[i], 3),
                        DetectedType = contentType.Key,//查找值名称
                        DetectedIndex = contentType.Value,
                        DetectedTypeDisplay = contentType.Key,//StringUtils.GetDataDisPlay(contentType.Key),//通过通用字符查找
                        Plcip = dataSource,
                        PartCode = partcode,
                        DetectedStatus = detectedStatus,
                        Description = channelCode
                    });
                }

            }
            catch (Exception ex)
            {
                AddLogEventHandler?.Invoke(channelCode + "件OP20使用批量获取测试时出错：" + ex.ToString(), dataSource);
            }
            return details;
        }

        /// <summary>
        /// 保存数据
        /// </summary>
        /// <param name="data">数据</param>
        /// <param name="keyenceDataDetailList"></param>
        /// <returns></returns>
        public ResultReturn SaveData(dynamic data, string channelCode)
        {
            try
            {
                string request = JsonConvert.SerializeObject(data);
                AddLogEventHandler?.Invoke(channelCode + "件OP20保存参数：" + request);
                if (channelCode == "B")
                {
                    Thread.Sleep(500);
                }
                string response = GetApiUtils.GetPostApi(request, sysModel.webApiUrl + "api/VoltageWithstand/Add").GetAwaiter().GetResult();
                return JsonConvert.DeserializeObject<ResultReturn>(response);
            }
            catch (Exception ex)
            {
                //Log4NetAppend(runType.ToString() + "数据存储报错：" + ex.ToString());
                AddLogEventHandler?.Invoke(channelCode + "件OP20数据存储报错：" + ex.Message);
            }
            return MessageInfoUtils.Fail();
        }

    }
}
